home *** CD-ROM | disk | FTP | other *** search
- Music-X Magic:
- Soup Up Your Sequencer With ARexx
-
- Copyright 1994 by Daniel J. Barrett
- Email: dbarrett@ora.com
-
- *** This article may be freely distributed, as long as it ***
- *** is distributed in its entirety, without modification. ***
-
- After a several year wait between updates, Music-X 2.0 finally
- arrived last Spring. One of the significant changes is that the program
- now supports ARexx, the Amiga's inter-program communication language. This
- is very good news: you can now extend Music-X's capabilities in powerful
- ways by writing "scripts" that operate on your sequences. For example,
- scripts can count the number of musical events in a sequence, transpose
- your music in various ways, or perform algorithmic composition. You can
- even make Music-X communicate with other ARexx compatible programs (more
- than 400 exist) to increase your power even further. For example, you can
- send data from Music-X directly into Deluxe Music 2.0 for musical notation,
- or communicate with a statistical package to analyze your sequences.
-
- Unfortunately, the ARexx documentation for Music-X is very sketchy.
- The manual is brief, omits some vital facts, and the example scripts
- mentioned in the manual (page 22) were omitted from the program. This
- article clarifies the manual, reveals the missing information, and teaches
- you how to write several useful scripts. This article assumes that you
- have at least looked at the ARexx chapter of the upgrade manual; keep it
- nearby for reference.
-
-
- A MOTIVATING EXAMPLE
-
- Let's begin with a simple script that transposes all the notes in
- your sequence upward by a perfect fifth (7 semitones). The numbers 1-12 on
- the left side are not part of the script; they are for our reference only.
-
- 1 /* Transpose up by a perfect fifth. */
- 2 OPTIONS RESULTS
- 3 BeginScan ALL
- 4 NextEvent
- 5 DO WHILE RESULT = 1
- 6 IF Event.Type = "NOTE" THEN DO
- 7 Event.Num = Event.Num + 7
- 8 ReplEvent
- 9 END
- 10 NextEvent
- 11 END
- 12 EndScan
-
- Let's examine what each line means.
-
- 1. A comment. Every ARexx script must begin with a comment;
- this is required, or else the script will not work.
- 2. Tell ARexx to report the results of certain commands in
- a variable called "RESULT". We need this variable on
- line 5.
- 3. Tell Music-X that we want to examine (scan through) all
- the events in the current sequence.
- 4. Read the first event. Its data is automatically stored in
- a special variable called "Event".
- 5-11. This "loop" is the heart of the script. As each event is
- read, its type is checked. If it is a NOTE event, add 7 to
- its note number, and use "ReplEvent" to make the change
- permanent. No matter what, we move to the next event and
- repeat. When there are no more events, "NextEvent" will
- fail, RESULT will equal zero (meaning failure), and the
- loop ends.
- 12. Tell Music-X we are done scanning the sequence.
-
- Type this script into a file called "Transposer.mxe". Now load
- a sequence into the Bar Editor, choose "Rexx..." from the Modules menu,
- use the file requestor to locate your Transposer.mxe script, and double-click
- on the script name. Voila! Your notes have been transposed.
-
-
- BASIC CONCEPTS
-
- ARexx support in Music-X is handled by a new module called
- RexxEdit. This module is automatically installed when you use the Music-X
- installation program. However, due to a bug in the installation, all your
- modules may not be accessible due to incorrect path names. If you
- encounter this, then exit Music-X, run the "Install Modules" program, click
- on each module name and remove the leading colon ":" from its Path, choose
- "Save", and restart Music-X.
-
- In a nutshell, RexxEdit allows you to do four kinds of operations:
-
- 1. Examine, add, delete, and change data in sequences.
- 2. Display requestors with a variety of gadgets for user input.
- 3. Get information about the bar editor: grid size,
- selected regions, step size, etc.
- 4. Communicate with other ARexx-compatible programs.
-
- In addition, RexxEdit does NOT allow you to:
-
- 1. Control recording and playback.
- 2. Control the Tool List in the Bar and Event Editors.
- 3. Use the cut, copy, and paste features.
- 4. Display or hide events in the Bar and Event Editors.
- 5. Affect the controls on the Sequencer, Filters, Samples, and
- Librarian pages.
-
- Perhaps a later version of Music-X will support such operations; but given
- how long it took for the 2.0 update, I have my doubts.
-
-
- OPERATIONS ON SEQUENCES
-
- Scripts that operate on sequences typically look a lot like
- our "Transposer.mxe" example. First, BeginScan must be called to examine
- the sequence. This is followed by a loop which examines each event using
- NextEvent and processes it in some way. When NextEvent returns "0" in the
- RESULT variable, the loop is finished, and we call EndScan.
-
- If you plan to add events to a sequence using AddEvent, there is
- an undocumented step which you MUST do: initialize the "Event" variable.
- This is done by placing the line
-
- Event. = ""
-
- once in your script, before any call to AddEvent. Note that the
- period after "Event" is mandatory because it is a stem variable. It
- doesn't matter what value you assign here; for example,
-
- Event. = 192873
-
- will work equally well.
-
- As an example, let's modify Transposer.mxe so instead of moving
- the notes, it adds new notes 7 semitones above the originals. For
- example, every C will get a new G added above it. This requires two
- changes: initialize the "Event" variable (say, between lines 2 and 3),
- and change the ReplEvent on line 8 to AddEvent. Store the script in a new
- file called Interval.mxe and test it out.
-
-
- REQUESTORS AND USER INPUT
-
- Our Transposer.mxe script is useful but limited. What if you want
- to transpose notes by sevenths instead of fifths? Do we need a whole new
- script for every kind of transposition? Nope! In this section, we will
- add a requestor to Transposer.mxe with several gadgets, allowing user
- control over the script's behavior.
-
- RexxEdit can display three kinds of requestors: a file requestor
- (MXFile), a "tell the user" requestor (MXReport), and a gadget-filled
- requestor for user input (MXRequest). The first two are well explained on
- page 46 of the upgrade manual. Our example will use the more complicated
- MXRequest. There are four steps to using it:
-
- 1. Decide whether you want a 1-column or 2-column requestor,
- using the MXColumn command. (Optional.)
-
- 2. Define your gadgets. Your choices are:
-
- MXButton On/Off buttons.
- MXSlider Sliders with positive values.
- MXMirror Sliders with negative and positive values.
- MXString String gadgets for text input.
- MXNoteSize The Music-X note duration control.
- MXLabel Plain text; not for user input.
-
- 3. Display the requestor with the MXRequest command.
-
- 4. Read the gadgets with the MXValue command to find out the user's
- selections.
-
- Our example lets the user choose a transposition interval, whether
- to replace or add notes, and whether to affect all notes or just
- selected/marked notes. First, let's design the requestor.
-
- 1 /* A requestor for transposing. */
- 2 OPTIONS RESULTS
- 3 MXMirror "Semitones:,127"
- 4 MXRadio "Replace existing notes,Add new notes"
- 5 MXRadio "All notes,Selected notes only"
- 6 MXRequest "My Transposer"
-
- Lines 3-5 define three gadgets: a "Semitones" slider running from -127 to
- +127, a pair of buttons for choosing replace or add, and another pair of
- buttons for choosing all or selected notes. Line 6 actually displays the
- requestor with our gadgets, as shown in Figure 1. To display it yourself,
- save lines 1-5 in a script called "Requestor.mxe" and execute it. Play
- around with the gadgets all you like, but remember that this requestor will
- have no actual effect on your sequence... yet.
-
- Continuing, let's find out what the user chose to do. If the
- user clicked CANCEL, the RESULT variable will have value 0. If so,
- we choose to exit immediately:
-
- 7 IF RESULT = 0 THEN
- 8 EXIT
-
- Next, we check our three defined gadgets using MXValue. To read the
- first gadget, use "MXValue 1"; for the second, "MXValue 2"; etc. The gadget
- value is returned in the RESULT variable. For "Semitones" slider, we store
- the results in a variable "semitones":
-
- 9 MXValue 1
- 10 semitones = RESULT
-
- The "add/replace" radio buttons have value 0 if the first button was
- chosen, or a 1 for the second button:
-
- 11 MXValue 2
- 12 add = RESULT
-
- For the "all/selected events" buttons, we set the variable "scanType" to
- "ALL" or "SELECTED" appropriately. These words have special value for
- the BeginScan command later:
-
- 13 MXValue 3
- 14 IF RESULT = 0 THEN
- 15 scanType = "ALL"
- 16 ELSE
- 17 scanType = "SELECTED"
-
- Save lines 1-17 in a file called "Requestor2.mxe", execute it, play with
- the gadgets, and see what happens.
-
- Now we are done with gadgets and user input, so it's time to do
- the actual transposition.
-
- 18 Event. = ""
- 19 BeginScan scanType
- 20 NextEvent
- 21 DO WHILE RESULT = 1
- 22 IF Event.Type = "NOTE" THEN DO
- 23 Event.Num = Event.Num + semitones
- 24 IF add = 1 THEN
- 25 AddEvent
- 26 ELSE
- 27 ReplEvent
- 28 END
- 29 NextEvent
- 30 END
-
- Note how similar this is to the loop in Transposer.mxe. The only
- differences are in lines:
-
- 18. Initialize the Event variable so we can add events.
- 19. BeginScan is instructed to scan ALL or SELECTED events,
- based on the user choice.
- 23. We now add the value "semitones" instead of 7.
- 24-27. Depending on the user's choice, we either add or replace
- the notes we transpose.
-
- Put lines 1-30 in a file called NewTransposer.mxe, and have fun
- with this highly useful script! If you try to transpose notes higher than
- MIDI allows (127), Music-X will "wrap then around" to 0 again; similarly
- for note numbers below 0. A note of caution: this script has very little
- error checking. You really should check the value of RESULT after the
- BeginScan, AddEvent, and ReplEvent commands to make sure they worked.
-
-
- EXAMINING THE BAR EDITOR
-
- In this section, we will build a script for adding pitch bend to a
- marked or selected region. Pitch bend events will be added, one at a time,
- at regular intervals in the region. The user may define how far apart
- the pitch bend events are. When followed by Music-X's Sculpt tool, this
- script will let you create interesting pitch-bend shapes.
-
- Bar Editor information is examined by using the GetBarData command.
- This command fills in the variable "BarData" with information like the
- current grid size, measure size, beginning and end of a marked region, etc.
- GetBarData is used like this:
-
- 1 /* Bar Data example with pitch bend events. */
- 2 OPTIONS RESULTS
- 3 GetBarData
- 4 IF RESULT = 0 THEN DO
- 5 MXReport "Could not get bar data."
- 6 EXIT
- 7 END
-
- Next, we detect whether there is a region defined.
-
- 8 IF BarData.Select = "NONE" THEN DO
- 9 MXReport "No region is marked/selected."
- 10 EXIT
- 11 END
-
- Save lines 1-11 to a file called "CheckRegion.mxe" and execute it.
- If no region is marked or selected, the script will display the MXReport
- requestor.
-
- Next, we allow the user to choose the spacing between the pitch
- bend events, using an MXNoteSize gadget, and the MIDI channel for the
- events, using a slider gadget. We store the user's choices in the
- variables "spacing" and "midiChannel", respectively.
-
- 12 MXNoteSize "Set Spacing:"
- 13 MXSlider "MIDI Channel:,1,16,1"
- 14 MXRequest "Add Pitch Bend Events"
- 15 IF RESULT = 0 THEN
- 16 EXIT
- 17 MXValue 1
- 18 spacing = RESULT
- 19 MXValue 2
- 20 midiChannel = RESULT - 1
-
- The reason for "RESULT - 1" is that Music-X stores MIDI channels 1-16
- as 0-15 internally. Add lines 12-20 to your script so you can see the
- requestor in Figure 2.
-
- Next, we locate the beginning and end of the region. Time in
- Music-X is measured in bars (measures) and clocks (clock ticks in each
- measure). For example, a note might appear in bar 17, clock 2475.
- Information about bars and clocks is stored in the variables:
-
- BarData.Start.Bars Measure number of the start of the region.
- BarData.Start.Clocks Clock number of the start of the region.
- BarData.Stop.Bars Measure number of the end of the region.
- BarData.Stop.Clocks Clock number of the end of the region.
- BarData.Measure Number of clocks per measure.
-
- We use our own variable "currentTime" to represent the current
- location in the region as we add events. As the script progresses, we
- repeatedly add a number of clocks (stored in the "spacing" variable) to the
- current time. However, when adding an event, we need to know the Bars and
- Clocks values, which will require a little math.
-
- Given the measure number and clock number of a Music-X event, the
- formula for calculating its location in clocks is:
-
- (Measure number) * (Clocks per Measure) + (Clock number)
-
- Thus, in our script, we compute the starting and ending times of our
- region, in clocks:
-
- 21 currentTime = BarData.Start.Bars * BarData.Measure ,
- + BarData.Start.Clocks
- 22 endTime = BarData.Stop.Bars * BarData.Measure ,
- + BarData.Stop.Clocks
-
- (Note: In ARexx, a comma means "continued on the next line." If you can
- fit each command on one line -- not possible on this magazine page -- then
- you must omit the commas.)
-
- Next, we prepare to scan the region. Just for fun, while the
- script is working, we change the pointer to the "sleeping cloud" to
- indicate work is being done.
-
- 23 MXPointer "SLEEPY"
- 24 Event. = "" /* Initialize Event variable */
- 25 BeginScan
-
- Since we are adding pitch bend events, we can fill in some of
- the Event variable fields that will remain constant: the event type,
- the MIDI channel, and an event value (we choose +8192, which is zero
- pitch bend).
-
- 26 Event.Type = "PBEN"
- 27 Event.Channel = midiChannel
- 28 Event.Num = 8192
-
- Finally, it is time to add pitch bend events! To add them at the
- right locations, we must calculate the Bar and Clock numbers where they
- should be added. The bar number is obtained using integer division (the
- "%" operator), and the clock number using the "mod" or "remainder" function
- (the "//" operator):
-
- 29 DO WHILE currentTime <= endTime
- 30 Event.Start.Bars = currentTime % BarData.Measure
- 31 Event.Start.Clocks = currentTime // BarData.Measure
- 32 AddEvent
- 33 currentTime = currentTime + spacing
- 34 END
-
- When the loop is done, clean up and exit.
-
- 35 EndScan
- 36 MXPointer "NORMAL"
-
- Save lines 1-36 in a file called "PitchBend.mxe". To use this
- script, first mark a region or select some events. Second, run the
- PitchBend.mxe script. Third, use the Sculpt Tool to shape the pitch bend
- events the way you want them. Enjoy!
-
- Note: RexxEdit has a bug concerning marked regions. If a region
- appears to be marked, but you keep getting the requestor "No region is
- marked/selected," try marking the region again or using the Select tool
- instead of Mark. (See "TECH TALK" below for more information.)
-
- Another note: the above assumes you are using "relative time"
- sequences, not "absolute time" sequences. If you use absolute time
- sequences, then time is measured in quarter frames instead of clocks;
- see the manual for more information.
-
-
- COMMUNICATING WITH OTHER PROGRAMS
-
- Using the ARexx "ADDRESS" command, Music-X scripts can talk to
- other ARexx-compatible products such as Deluxe Music 2.0, Bars and Pipes
- Professional, One Stop Music Shop, and even non-music products. How about
- using SuperBase Professional to store your Music-X sequences? VLT for
- uploading and downloading sequences? AmigaVision for multimedia? The
- possibilities are numerous and exciting.
-
- Communicating with another program has 4 steps.
-
- 1. Find out the ARexx port names of the other program, by
- consulting its documentation.
-
- 2. Store Music-X's port name in a variable for safekeeping,
- using the Address() command. (See "TECH TALK", below,
- if you are interested in the reason.)
-
- 3. Use the Show("P") command to make sure that the other programs
- are running. If not, then your script run them, using the
- "WaitForPort" command to wait until the program is running.
-
- 4. Use the "ADDRESS" command to talk to the other programs.
-
- In this section, we write scripts to communicate with Electronic
- Arts' Deluxe Music 2.0 notation program, port name "DMUSIC", and Oxxi's
- TurboText editor, port name "TURBOTEXT". Our first script sends the
- currently selected Music-X note to Deluxe Music, inserting it at Deluxe
- Music's current cursor location.
-
- First, we save Music-X's port name in a variable "myAddress":
-
- 1 /* Example script using Deluxe Music 2.0. */
- 2 OPTIONS RESULTS
- 3 myAddress = Address()
-
- Next, we make sure that something is selected.
-
- 4 GetBarData
- 5 IF BarData.Select ~= "SELECT" THEN DO
- 6 MXReport "Nothing is selected."
- 7 EXIT
- 8 END
-
- Next, we make sure that the selected event is a note.
-
- 9 BeginScan "SELECTED"
- 10 NextEvent
- 11 EndScan
- 12 IF Event.Type ~= "NOTE" THEN DO
- 13 MXReport "You must select a note."
- 14 EXIT
- 15 END
-
- Next, we make sure Deluxe Music is running by looking for its
- ARexx port. If a port named "DMUSIC" does not exist, then we run
- Deluxe Music.
-
- 16 IF ~Show('P', 'DMUSIC') THEN DO
- 17 ADDRESS COMMAND
- 18 "Run < NIL: > NIL: DMusic"
- 19 WaitForPort "DMUSIC"
- 20 END
-
- Now, we are ready to send the note from Music-X to Deluxe Music.
-
- 21 ADDRESS "DMUSIC"
- 22 INSERTITEM NOTE PITCH Event.Num
- 23 NEXT NOTE
-
- Finally, we pop the Deluxe Music screen to the front to see our
- handiwork:
-
- 24 SCREENTOFRONT
-
- Save lines 1-24 to a file called "DMusic.mxe", execute the script,
- and watch what happens. With some work, this script could be the basis for
- a whole direct interface between Music-X and Deluxe Music. You may notice
- that we didn't use the myAddress variable. This is because the script did
- all its Music-X communication first, and then all its Deluxe Music
- communication.
-
- The next example is more complex, sending information about notes
- and their velocities from a sequence into a TurboText edit window. We
- start off with the usual, saving Music-X's address and invoking TurboText
- if it is not running:
-
- 1 /* Send note information to TurboText. */
- 2 OPTIONS RESULTS
- 3 myAddress = Address()
- 4 IF ~Show("P", "TURBOTEXT") THEN DO
- 5 ADDRESS COMMAND
- 6 "TTX > NIL: BACKGROUND NOWINDOW"
- 7 WaitForPort "TURBOTEXT"
- 8 END
-
- Next, we tell TurboText to open a new edit window. The name of
- that window (its own ARexx port) is returned in the RESULT variable:
-
- 9 ADDRESS "TURBOTEXT"
- 10 OpenDoc
- 11 windowName = RESULT
-
- Finally, we talk to Music-X again, scan through the sequence,
- picking out notes, and sending their information to the TurboText window:
-
- 12 ADDRESS VALUE myAddress
- 13 BeginScan ALL
- 14 NextEvent
- 15 DO WHILE RESULT = 1
- 16 IF Event.Type = "NOTE" THEN DO
- 17 ADDRESS VALUE windowName
- 18 Insert "Note" Event.Num "Vel" Event.Attack
- 19 InsertLine
- 20 ADDRESS VALUE myAddress
- 21 END
- 22 NextEvent
- 23 END
- 24 EndScan
-
- I realize that these Deluxe Music and TurboText scripts are harder
- to understand than the previous ones. This is because each program has its
- own set of commands, such as "OpenDoc" and "Insert" in the TurboText example.
- Writing scripts that connect two programs means learning the command sets for
- both programs, and this may require careful reading of each program's
- documentation, as well as a lot of hair pulling!
-
-
- REXXEDIT TIPS AND TRICKS
-
- Here is a set of (mostly undocumented) tips and tricks I've
- discovered while writing Music-X scripts.
-
- o The MXReport command is great for helping to debug your scripts.
- If you want to see the value of a variable (say, "myVar") at any
- time, just insert the line "MXReport myVar" at the appropriate spot
- in the script. If you need more space for messages, use MXLabel
- and MXRequest.
-
- o If your gadgets in an MXRequest don't have enough space between
- them for your tastes, the command
-
- MXLabel ""
-
- will insert a blank line. Remember to count this MXLabel
- command when using MXValue to read gadget values!
-
- o By default, the RexxEdit module is available only inside the Bar
- and Event Editors. But you can use the "Install Modules" script
- to make it available in other pages. Simply click on the
- other checkboxes in the "Install Modules" window, quit and
- restart Music-X, and you're set. The ARexx functionality will
- be more limited on other pages, because there is no "current
- sequence" being displayed, but you can still do some interesting
- things.
-
- o The "Event" variable has different fields depending on what
- type of event it contains. For example, a NOTE event has its
- velocity in Event.Attack, but it does not use Event.Pressure.
- You must write your scripts carefully so they examine ONLY
- the Event fields that apply to the current event. Read pages
- 49-52 carefully to learn which event fields are valid.
- (See also the next item.)
-
- o The spacing and boldfacing on pages 49 and 50 of the Music-X 2.0
- Upgrade Manual is messed up, making it difficult to distinguish
- event types from variables. Four variable names are incorrectly
- boldfaced: EVENT.DEM belongs to the TSIG event, EVENT.TRANSPOSE
- and EVENT.CUT belong to the PSEQ event, and EVENT.ATTACK belongs
- to the NOTE event.
-
- o The range of pitch bend values goes from -8192 to +8191, with
- 0 being zero pitch bend. PBEN event values
- (Event.Num) are really between 0 and 16383; that
- is, 8192 higher than the actual bend value. If you use an MXMirror
- gadget to get pitch bend values from the user, remember to
- add 8192 to the result before storing it in Event.Num.
-
- o Since pitch bend goes from -8192 to +8191, not +8192. If you use an
- MXMirror slider for pitch bend, the highest positive value +8192
- is invalid. So your script may need code like this:
-
- MXValue 3 /* Get the MXMirror value. */
- value = RESULT
- IF value = 8192 THEN /* Disallow +8192 value. */
- value = 8191
-
-
- REXXEDIT PROBLEMS
-
- One of RexxEdit's omissions is that it has no ARexx command for
- disabling user input. While a script is running, all gadgets on the Music-X
- screen are "live," even though they do not appear to respond, and they will
- react to all of your inadvertent keystrokes and mouseclicks when the script
- finishes. So, while a script is executing, don't click on any gadgets
- except those in an ARexx requestor (e.g., MXRequest). As a visual aid, do
- "MXPointer SLEEPY" while a script is running.
-
- Second, RexxEdit cannot abort a script in progress. Suppose your
- script scans a sequence with a loop, but you forget to call NextEvent in
- it. You now have an infinite loop and no way to stop it except by
- rebooting your Amiga.
-
- Third, as mentioned earlier, Music-X "forgets" any marked region
- every time RexxEdit is run. This is especially confusing because the
- region on the screen still appears to be marked. The problem does not
- occur with selected events. To get around this problem, either use
- selecting instead of marking when possible, or re-mark the region after
- each ARexx macro is run. There is also a problem with the selected
- events. The Select tool works fine. However, if you use the Move or Add
- tools and click on an event, it highlights as if it were selected. Other
- modules like the Quantizer will treat it as selected. However, RexxEdit
- does not think it is selected. The moral: if a script requires selected
- events, you must use the Select tool.
-
-
- TECH TALK
-
- If you've used ARexx before, you may notice that Music-X's
- interface is unusual in several notable ways. First, its ARexx port name
- is completely undocumented. By using the command
-
- MXReport Address()
-
- I discovered that the name is "MUSIC-X AREXX EDIT". However, this
- information is of no use, because of a second non-standard feature: it's
- impossible to control Music-X from another program. All scripts must be
- run from inside Music-X. This is because the ARexx port belongs to
- RexxEdit, not to Music-X. When RexxEdit is not running, the port
- disappears, and when RexxEdit is running, Music-X occupies its full
- attention.
-
- A third oddity involves ARexx return codes. By convention, ARexx
- commands return their success (1) or failure (0) values in the "RC"
- variable. Music-X uses the "RESULT" variable instead, which is usually
- reserved for more complex return values. RC is unused. Until you figure
- this out, you'll be scratching your head wondering why your error-checking
- doesn't work.
-
-
- GOOD LUCK!
-
- By using ARexx and RexxEdit, you can personalize Music-X with
- powerful new tools of your own invention. It takes some effort to get
- used to ARexx, but the results can really be worth it.
-
- ===
-
- Daniel J. Barrett has been making electronic and computer music since
- 1979, and has been an Amiga owner since 1987.
-